﻿using System;
using System.Collections.Generic;
using static Debugger;

namespace Module.FlowChart.RunAble.Logic.Sequential
{
    internal enum RunState
    {
        NotRunning,
        Running,
        WaitForStop,
    }
    internal class RunnerHandles
    {
        public Action<int> OnRunNode;//当节点正在被执行时 通知界面高亮节点
        public Action<string> CMD;
        /// <summary>
        /// 设置节点可见性并通知界面重绘
        /// </summary>
        public Action<int, bool> SetNodeVisible;
        public Action<bool> SetAllNodeVisible;
        public Func<int, List<int>> GetNodeNear_NotVisible;//获取一个节点旁边不显示的节点
        public Func<int> GetSelectedNode;
        public Func<int> GetStartNode;

        public RunnerHandles()
        {
            OnRunNode = null;
            CMD = null;
            SetNodeVisible = null;
            SetAllNodeVisible = null;
            GetNodeNear_NotVisible = null;
            GetStartNode = null;
        }


    }
    internal class FCRunner
    {
        private RunnerHandles Handles;
        internal bool IsRunning => RunState != RunState.NotRunning;

        public RunState RunState { get; private set; }
        public int CurrentShow { get; private set; }//新显示的节点
        public List<int> CanShow { get; private set; }//将要显示的节点


        public FCRunner()
        {
        }


        private void RunInit()
        {
            RunState = RunState.Running;
            Handles.SetAllNodeVisible(false);
            Handles.SetNodeVisible(CurrentShow = Handles.GetStartNode(), true);
            CanShow = new List<int>(Handles.GetNodeNear_NotVisible(CurrentShow));
            if (CanShow.Count == 0)
                RunState = RunState.WaitForStop;
        }

        private void RunOneStep(int select)
        {
            CurrentShow = CanShow[Utility.Limit(select, 0, CanShow.Count - 1)];
            Handles.SetNodeVisible(CurrentShow, true);
            CanShow.Remove(CurrentShow);
            CanShow.AddRange(Handles.GetNodeNear_NotVisible(CurrentShow));
            if (CanShow.Count == 0)
                RunState = RunState.WaitForStop;
        }
        IEnumerator<bool> ieSync;
        public IEnumerator<bool> RunSync(RunnerHandles h)
        {

            Assert(h != null);
            if (RunState != RunState.NotRunning)
                throw new Exception("在运行中，无法重新运行");
            Handles = h;
            RunInit();
            yield return true;
            while (RunState != RunState.WaitForStop)
            {
                RunOneStep(Handles.GetSelectedNode());
                yield return true;
            }
            RunState = RunState.NotRunning;
            Handles.SetAllNodeVisible(true);
            yield return false;
        }
        public void StartSync(RunnerHandles h)
        {
            ieSync = RunSync(h);
            ieSync.MoveNext();
        }

        public bool NextSync()
        {
            Check(IsRunning); ieSync.MoveNext();
            return ieSync.Current;
        }
        public void StopSync()
        {
            Check(IsRunning);
            RunState = RunState.NotRunning;
            Handles.SetAllNodeVisible(true);
        }
    }
}
